package com.sankuai.aspect;

import com.sankuai.annotaion.CheckParam;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @Author：YH
 * @Description：
 * @Date:Created in 2022/1/18 0:16
 */

@Component
@Aspect
public class CheckParamAspect {

    private static Logger LOGGER = LoggerFactory.getLogger(CheckParamAspect.class);

    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public void methodPointCut() {
    }

    /**
     * 环绕切入方法
     **/
    @Around("methodPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        //获取方法上的注解
        MethodSignature msig = (MethodSignature) point.getSignature();
        Method method = msig.getMethod();

        if (Objects.nonNull(method)) {
            method.getAnnotation(CheckParam.class);
        }

        LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
        //这里返回的是切入点方法的参数列表
        Object[] args = point.getArgs();
        for (int i = 0; i < args.length; i++) {
            Object obj = args[i];
            MethodParameter mp = new MethodParameter(method, i);
            mp.initParameterNameDiscovery(u);
            GenericTypeResolver.resolveParameterType(mp, method.getClass());//Spring处理参数
            //String paramName = mp.getParameterName();//参数名
            CheckParam anno = mp.getParameterAnnotation(CheckParam.class);//参数注解
            if (anno != null) {
                check(obj);
            }
        }
        return point.proceed();
    }

    /**
     * 校验成员变量
     **/
    private void check(Object obj) throws IllegalAccessException {
        Class clazz = obj.getClass();
        for (Field field : clazz.getDeclaredFields()) {
            CheckParam cp = field.getAnnotation(CheckParam.class);
            if (cp != null) {
                check(obj, clazz, field, cp);
            }
        }
    }

    /**
     * 取出注解，校验变量
     **/
    private void check(Object obj, Class clazz, Field field, CheckParam cp) throws IllegalAccessException {
        if (cp.notNull()) {
            field.setAccessible(true);
            Object f = field.get(obj);
            if (StringUtils.isEmpty(f)) {
                LOGGER.error("[CheckParamAspect.check]出现异常error");
                throw new IllegalArgumentException("类" + clazz.getName() + "成员" + field.getName() + "自定义注解检测到非法参数");
            }
        }
    }
}
